// =================================================================
// Name: FSManager.h
// Desc: Contains FSManager class to manage filesystem states
// =================================================================

#ifndef FSMANAGER_H
#define FSMANAGER_H

// =================================================================
// INCLUDES
// =================================================================

#include <fstream>
#include <string>
#include "Directory.h"
#include "Inode.h"
#include "IndirectBlock.h"
#include "Superblock.h"
#include "Block.h"

using namespace std;

// =================================================================
// CLASSES
// =================================================================

// =================================================================
// Name: FSManager
// Desc: Manages the states of the filesystem
// =================================================================
class FSManager {

  public:

    FSManager(string filename);
    ~FSManager();

    FILE* GetFP();

    Directory *GetCurrentDirectory();
    void SetCurrentDirectory(Directory *dir);

    Directory *GetRootDirectory();
    void SetRootDirectory(Directory *dir);

    Directory *ReadDirectory(string path);
    void WriteDirectory(Directory *dir);

    void WriteIndirectBlock(IndirectBlock *block, int index);
    IndirectBlock *ReadIndirectBlock(int index);

    Inode *ReadInode(int index);
    void WriteInode(Inode *node, int index);

    void ReadSuperblock();
    void WriteSuperblock();

    void WriteFile(string data, File *file, bool isDir = false);
    string ReadFile(File *file, int bytes);

    Superblock *GetSB();
    void SetSB(Superblock* sb);

    void InsertOpenFile(int fd, File *file);
    void RemoveOpenFile(int fd);
    int GetNextAvailableFD();
    File *GetOpenFile(int fd);

    void WriteCache(int block_index,Block *block);
    Block *ReadCache(int block_index);

    void Reset();

  private:
    
    void WriteData(string& data, File *file, Inode* node);
    string ReadData(File *file, Inode *node, int bytes);

    int MakeSinglyIndirect(int index, int &num_blocks);
    int MakeDoublyIndirect(int index, int &num_blocks);
    int MakeTriplyIndirect(int index, int &num_blocks);
    void UpdateLRU(int block_index);
    
    FILE* fp;                // File pointer to open FS_NAME file
    Superblock *sb;          // Pointer to superblock of filesystem
    Directory *root_dir;     // Pointer to the root directory
    Directory *current_dir;  // Pointer to the current directory
    
    map<int, File *> open_files; // Stores open file descriptors
    map<int, Block *> cache;     // Stores cache of size CACHE_SIZE
    vector<int> cache_lru;       // Keeps track of blocks in cache
};

#endif // FSMANAGER_H
